-module(lwapp_tunnel_dispatcher).
-include("protocol.hrl").
-behaviour(gen_server).
-export([start/0,start_link/0,init/1,handle_call/3,handle_cast/2,handle_info/2,terminate/2,code_change/3]).
-export([do/2]).
-define(SERVER,?MODULE).
do(packet_comming,Packet_Tuple) ->
	gen_server:cast(?SERVER,{packet_comming,Packet_Tuple});
do(dump,ac) ->
	io:format("dump ac map ~p ~n",[gen_server:call(?SERVER,dump_ac)]).
start()  ->
	gen_server:start({local, ?SERVER}, ?MODULE, [], []).
start_link() ->
	gen_server:start_link({local, ?SERVER}, ?MODULE, [], []).
init(_) ->
	io:format("~s start...~n",[?SERVER]),
	{ok,{runing,{}}}.
handle_call(dump_ac,_,State) ->
	{reply,get(),State};
handle_call(_,_,State) ->
	{reply, {error,"no func define"}, State}.
	
handle_cast({packet_comming,P_Tuple},{runing,Sta}) ->
	case P_Tuple#packet_tuple.packet of
	<<0:4,_Slot_ID:4,_Fragement_ID:8,Length:16,RSSI_SNR:16,WLANPacket/binary>> when Length > 32 ->
		prehandle_80211(#lwapp_protocol{rssi = RSSI_SNR},P_Tuple#packet_tuple{packet=WLANPacket,size=Length});
	_ ->
		error_logger:info_report([{packet_ignore,P_Tuple},{reason,"unrecognized lwapp header"}])
	end,
	{noreply,{runing,Sta}};
handle_cast(_, State) ->
	{noreply,State}.
handle_info(_, State) ->
	{noreply,State}.
terminate(_, _) ->
	ok.
code_change(_, State, _) ->
	{ok,State}.	
	
prehandle_80211(LWAPP_Context,P_Tuple) ->
	[Udp_Info|[Ip_Info|_]] = P_Tuple#packet_tuple.context,
	case {get(Ip_Info#ip_protocol.source_ip),get(Ip_Info#ip_protocol.dest_ip)} of
	{undefined,undefined} ->
		error_logger:info_msg("no ac found for ~p",[Ip_Info#ip_protocol.dest_ip]),
		forward_to_ac({check,Ip_Info#ip_protocol.dest_ip},
						P_Tuple#packet_tuple{
								context = [LWAPP_Context#lwapp_protocol{ap = Ip_Info#ip_protocol.source_ip,ac=Ip_Info#ip_protocol.dest_ip,dir=up}
										|P_Tuple#packet_tuple.context]});
	{undefined,Pid}	->
		forward_to_ac({Pid},						
						P_Tuple#packet_tuple{
								context = [LWAPP_Context#lwapp_protocol{ap = Ip_Info#ip_protocol.source_ip,ac=Ip_Info#ip_protocol.dest_ip,dir=up}
										|P_Tuple#packet_tuple.context]});
	{Pid,undefined} ->
		forward_to_ac({Pid},
						P_Tuple#packet_tuple{
								context = [LWAPP_Context#lwapp_protocol{ap = Ip_Info#ip_protocol.dest_ip,ac=Ip_Info#ip_protocol.source_ip,dir=down}
										|P_Tuple#packet_tuple.context]});
	_ ->
		%%error_logger:error_report([{logic_error,P_Tuple}|{reason,"duplicate ac ip addresses found in one packet"}])
		Packet_Index = (lists:last(P_Tuple#packet_tuple.context))#l1_protocol.index,
		gen_event:notify(unknown_packet_evt,skip,{lwapp,Packet_Index,{Ip_Info#ip_protocol.source_ip,Ip_Info#ip_protocol.dest_ip}})
	end.
	
forward_to_ac({Pid},P_Tuple) when is_pid(Pid) ->
	ac_80211_server_sup:forward(Pid,P_Tuple),
	ap_80211_server_sup:forward(P_Tuple);
	
forward_to_ac({add,AC_ip},P_Tuple) ->
	{ok,Child_Id} = ac_80211_server_sup:start_child(AC_ip),
	put(AC_ip,Child_Id),
	forward_to_ac({Child_Id},P_Tuple);
	
forward_to_ac({check,AC_ip},P_Tuple) ->   %%guess who is the ac.
	case P_Tuple#packet_tuple.packet of
	<<0:4,_Ver:4,_B/binary>> -> %% association
		forward_to_ac({add,AC_ip},P_Tuple);
	<<3:4,_Ver:4,_B/binary>> -> %% reassociation
		forward_to_ac({add,AC_ip},P_Tuple);
	<<4:4,_Ver:4,_B/binary>> -> %% probe
		forward_to_ac({add,AC_ip},P_Tuple);
	_ ->
		error_logger:info_report([{packet_ignore,P_Tuple},{reason,"no ac register"}])
	end.
	
